package com.cskaoyan.javase.reflect._5method;

import com.cskaoyan.javase.reflect.Person;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * Method表示成员方法
 *
 * @since 11:20
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws Exception {
        // 获取Person类的Class
        Class<?> perClazz = Class.forName("com.cskaoyan.javase.reflect.Person");
        for (Method method : perClazz.getMethods()) {
            System.out.println(method);
        }
        System.out.println("--------------------");
        for (Method declaredMethod : perClazz.getDeclaredMethods()) {
            System.out.println(declaredMethod);
        }

        // 用反射创建对象,然后调用成员方法
        Constructor<?> c = perClazz.getConstructor(int.class, String.class, String.class);
        System.out.println("---------------------");
        Person p = (Person) c.newInstance(18, "长风的女神", "男");
        System.out.println(p);
        System.out.println("---------------------");
        Method eatMethod = perClazz.getDeclaredMethod("eat", String.class);
        eatMethod.setAccessible(true);
        Object result = eatMethod.invoke(p, "拉面");
        // 方法是void,所以返回值是null
        System.out.println(result);

        System.out.println("------------------");

        Method eatFoodsMethod = perClazz.getMethod("eat", String[].class);
        String[] foods = {"茶颜悦色", "九转大肠"};
        // p.eat(foods);
        /*
            分析:
            invoke方法表示方法传入的实参用的类型是
            Object... args 是Object类型的可变参数
            实际上也就是需要传入一个Object数组
            这样给形参,让这个方法的灵活性很高,所有的类型都可以往里面传
            但是如果方法的形参类型是数组时,就会带来一定的问题
            如果方法需要的形参是数组,这时直接传入这个数组,就会让方法调用产生困惑:
            不清楚需要的是可变参数调用还是非可变参数调用。
            eat(String[] foods)真正需要的是String数组传入
            但是用反射时传入的是Object数组
            所以反射的方法当中,传入的Object数组当中装的就是String数组
            如果直接反射传入String数组,那么这个String数组究竟是直接传入还是用Object数组传入呢?
            这时就不清楚,就会产生困惑
            怎么解决?
                直接传入Object数组,让Object数组再封装一层String数组
            这一点了解即可,开发中不会很常见
         */
        // Confusing argument 'foods', unclear if a varargs or non-varargs call is desired. Single-item array is expected.
        // eatFoodsMethod.invoke(p, foods);
        String[] foods2 = {"海底捞", "麻辣烫"};
        eatFoodsMethod.invoke(p, new Object[]{
                foods
        });
        // eatFoodsMethod.invoke(p, foods, foods2);
    }
}
